﻿using System;
using ILRuntime.CLR.Method;
using Pumpkin.Utils;
using ILRTDomain = ILRuntime.Runtime.Enviorment.AppDomain;

namespace Pumpkin.FrameBase
{
    public static class ILRTUtils
    {
        private static ILRTDomain appdomain;
        public static ILRTDomain GetDomain()
        {
            return appdomain;
        }

        public static void SetDomain(ILRTDomain app)
        {
            if(appdomain != null)
            {
                throw new InvalidOperationException("ILRT AppDomain has already exist");
            }
            appdomain = app;
        }

        public static object Invoke(string clsName, string methodName, object obj, params object[] args)
        {
            return appdomain.Invoke(clsName, methodName, obj, args);
        }

        /// <summary>
        /// 存在优化空间，可以事先提取ILMethod
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="methodName"></param>
        /// <param name="args"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static object Invoke(this CrossDomainInstance obj, string methodName, params object[] args)
        {
            IMethod method = null;
            if (obj.CrossInfo.Methods.TryGetValue(methodName, out method))
            {
                return appdomain.Invoke(method, obj.Instance, args);
            }
            else
            {
                Log.LogInfo(obj.CrossInfo.ClassName + "'s method was not registed, this may cause low performance");
                return appdomain.Invoke(obj.CrossInfo.ClassName, methodName, obj.Instance, args);
            }
        }

        public static object Invoke(this CrossDomainInstance obj, string methodName)
        {
            IMethod method = null;
            if (obj.CrossInfo.Methods.TryGetValue(methodName, out method))
            {
                return appdomain.Invoke(method, obj.Instance, null);
            }
            else
            {
                Log.LogInfo(obj.CrossInfo.ClassName + "'s method was not registed, this may cause low performance");
                return appdomain.Invoke(obj.CrossInfo.ClassName, methodName, obj.Instance, null);
            }
        }

        public static object StaticInvoke(this CrossDomainInstance obj, string methodName)
        {
            return StaticInvoke(obj.CrossInfo, methodName);
        }

        public static object StaticInvoke(this CrossDomainInstance obj, string methodName, params object[] args)
        {
            return StaticInvoke(obj.CrossInfo, methodName, args);
        }

        public static object StaticInvoke(this CrossDomainInfo info, string methodName)
        {
            IMethod method = null;
            if (info.Methods.TryGetValue(methodName, out method))
            {
                return appdomain.Invoke(method, null, null);
            }
            else
            {
                Log.LogInfo(info.ClassName + "'s method was not registed, this may cause low performance");
                return appdomain.Invoke(info.ClassName, methodName, null, null);
            }
        }

        public static object StaticInvoke(this CrossDomainInfo info, string methodName, params object[] args)
        {
            IMethod method = null;
            if (info.Methods.TryGetValue(methodName, out method))
            {
                return appdomain.Invoke(method, null, args);
            }
            else
            {
                Log.LogInfo(info.ClassName + "'s method was not registed, this may cause low performance");
                return appdomain.Invoke(info.ClassName, methodName, null, args);
            }
        }
        /// <summary>
        /// 属性设置可优化，后期将一部分属性获取和设置变为函数实现
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="propertyName"></param>
        /// <param name="val"></param>
        /// <typeparam name="T"></typeparam>
        //public static void SetProperty<T>(this EntityObj entity, string propertyName, T val)
        //{
        //    var it = ILRTMain.GetDomain().LoadedTypes[entity.info.className];
        //    var type = it.ReflectionType;
        //    var fi = type.GetField(propertyName,
        //        System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        //    fi.SetValue(entity.instance, val);
        //}

        //public static T GetProperty<T>(this EntityObj entity, string propertyName)
        //{
        //    var it = ILRTMain.GetDomain().LoadedTypes[entity.info.className];
        //    var type = it.ReflectionType;
        //    var pi = type.GetProperty(propertyName);
        //    return (T)pi.GetValue(entity.instance, null);
        //}
    }
}